Skip to content

Media: Skip cross-origin isolation for third-party page builders#11170

Closed
adamsilverstein wants to merge 21 commits intoWordPress:trunkfrom
adamsilverstein:skip-page-builder-dip
Closed

Media: Skip cross-origin isolation for third-party page builders#11170
adamsilverstein wants to merge 21 commits intoWordPress:trunkfrom
adamsilverstein:skip-page-builder-dip

Conversation

@adamsilverstein
Copy link
Member

@adamsilverstein adamsilverstein commented Mar 5, 2026

Summary

  • Adds a check to skip Document-Isolation-Policy (DIP) when a third-party page builder overrides the block editor via a custom action query parameter
  • DIP isolates the document into its own agent cluster, which blocks same-origin iframe access that page builders rely on
  • Split out from Media: Use Document-Isolation-Policy for cross-origin isolation #11098 per review feedback to allow separate discussion of edge cases (e.g. Web Stories uses action=edit but replaces the block editor entirely)

See discussion: #11098 (comment)

Test plan

  • Verify the block editor still gets cross-origin isolation headers on standard post/page edit screens
  • Verify that a page builder using a custom action parameter (e.g. action=elementor) does NOT get DIP headers
  • Discuss edge cases where action=edit is used but the block editor is replaced (e.g. Web Stories)

Trac ticket: https://core.trac.wordpress.org/ticket/64803


Draft Commit Message

Editor: Skip cross-origin isolation for third-party page builders.

Document-Isolation-Policy (DIP) isolates the document and blocks same-origin iframe access that page builders rely on. Skip DIP setup when a third-party page builder overrides the block editor via a custom `action` query parameter.

Also gates `wp_is_client_side_media_processing_enabled()` on a secure context check, since `SharedArrayBuffer` requires a secure context (HTTPS or localhost).

Props adamsilverstein, westonruter, mukesh27, louiswol94, manhar, illuminea.
Fixes #64803.

@github-actions
Copy link

github-actions bot commented Mar 5, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @miriamelementor.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

Core Committers: Use this line as a base for the props when committing in SVN:

Props adamsilverstein, westonruter, mukesh27, louiswol94.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions
Copy link

github-actions bot commented Mar 5, 2026

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

adamsilverstein added a commit to adamsilverstein/wordpress-develop that referenced this pull request Mar 5, 2026
…ation.

Remove tests for the page builder action check that was moved to a
separate PR (WordPress#11170).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a check to skip Document-Isolation-Policy when a third-party page
builder overrides the block editor via a custom action parameter. DIP
isolates the document into its own agent cluster, which blocks
same-origin iframe access that these editors rely on.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@adamsilverstein adamsilverstein force-pushed the skip-page-builder-dip branch from 68f7673 to 3f563a1 Compare March 5, 2026 11:50
Copy link
Member

@mukeshpanchal27 mukeshpanchal27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @adamsilverstein

Left some feedback and questions.

// DIP isolates the document into its own agent cluster,
// which blocks same-origin iframe access that these editors rely on.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( isset( $_GET['action'] ) && 'edit' !== $_GET['action'] ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While implementing wp_set_up_cross_origin_isolation, was this issue discussed anywhere? If so, could you please share the reference links?

Discuss edge cases where action=edit is used but the block editor is replaced (e.g., Web Stories).

Also, do we have any research or data on how many plugins might be impacted by this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not an issue for Web Stories because it short-circuits here:

if ( ! $screen->is_block_editor() && 'site-editor' !== $screen->id && ! ( 'widgets' === $screen->id && wp_use_widgets_block_editor() ) ) {
return;
}

This is because it is filtering replace_editor in the same way that the latest Elementor is doing in elementor/elementor#34900.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, it also short-circuits here with the Classic Editor plugin.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While implementing wp_set_up_cross_origin_isolation, was this issue discussed anywhere? If so, could you please share the reference links?

@mukeshpanchal27 -

the original pr included this fix, but it was removed because it was deemed unrelated (#11098 (comment)).

Both changes came out of bugs reports after the release of beta 1 - https://core.trac.wordpress.org/ticket/64740 there is more discussion there about why the fix for Elementor was added

@adamsilverstein
Copy link
Member Author

In my testing with Elementor without this PR things seemed to be fixed, perhaps because we switched to using Document Isolation Policy. I will confirm this with their team, then I think we can close this PR as "working as expected".

@adamsilverstein adamsilverstein marked this pull request as draft March 10, 2026 17:43
@louiswol94
Copy link

In my testing with Elementor without this PR things seemed to be fixed, perhaps because we switched to using Document Isolation Policy. I will confirm this with their team, then I think we can close this PR as "working as expected".

@adamsilverstein Can you test by removing this filter? https://github.com/elementor/elementor/pull/34900/changes

This fix was added on our side in 3.35 (latest version). But all our users that have < 3.35 would be affected.

@adamsilverstein
Copy link
Member Author

In my testing with Elementor without this PR things seemed to be fixed, perhaps because we switched to using Document Isolation Policy. I will confirm this with their team, then I think we can close this PR as "working as expected".

@adamsilverstein Can you test by removing this filter? https://github.com/elementor/elementor/pull/34900/changes

This fix was added on our side in 3.35 (latest version). But all our users that have < 3.35 would be affected.

I was actually testing on an older version before upgrading and it seemed to work fine, but I will also try disabling the filter now that I have upgraded Elementor.

@westonruter
Copy link
Member

@louiswol94 I don't get any error with that line commented out.

However, I'm seeing something else unexpected here:

add_action( 'load-post.php', 'wp_set_up_cross_origin_isolation' );

I don't see that wp_set_up_cross_origin_isolation() is getting called at all when accessing the Elementor editor. However, if I change it to:

add_action( 'load-post.php', fn() => wp_set_up_cross_origin_isolation() );

Then it does run and I get an error in the console:

Uncaught SecurityError: Failed to read a named property 'elementorFrontend' from 'Window': Blocked a frame with origin "http://localhost:8000" from accessing a cross-origin frame.

And I see the Elementor loading spinner indefinitely:

image

Why wouldn't add_action( 'load-post.php', 'wp_set_up_cross_origin_isolation' ) work in Elementor?

@adamsilverstein adamsilverstein marked this pull request as ready for review March 10, 2026 17:59
@adamsilverstein
Copy link
Member Author

@louiswol94 - I did verify that Elementor loads without error even with that filter removed, so I'm not sure this PR is needed. It would still be good to address Weston's question above.

@westonruter
Copy link
Member

I can confirm that the patch fixes the issue in Elementor. However, I can only reproduce the issue if I do this change as well:

--- a/src/wp-includes/default-filters.php
+++ b/src/wp-includes/default-filters.php
@@ -679,7 +679,7 @@ add_filter( 'plupload_default_settings', 'wp_show_heic_upload_error' );
 // Client-side media processing.
 add_action( 'admin_init', 'wp_set_client_side_media_processing_flag' );
 // Cross-origin isolation for client-side media processing.
-add_action( 'load-post.php', 'wp_set_up_cross_origin_isolation' );
+add_action( 'load-post.php', fn() => wp_set_up_cross_origin_isolation() );
 add_action( 'load-post-new.php', 'wp_set_up_cross_origin_isolation' );
 add_action( 'load-site-editor.php', 'wp_set_up_cross_origin_isolation' );
 add_action( 'load-widgets.php', 'wp_set_up_cross_origin_isolation' );

(Aside from also commenting out the change introduced in elementor/elementor#34900.)

@louiswol94
Copy link

louiswol94 commented Mar 10, 2026

Hey guys...

Quick question:

Does DIP break same-origin contentWindow access?

According to this https://developer.chrome.com/blog/document-isolation-policy

Iframes isolated with Document Isolation Policy don't have synchronous DOM access to same-origin iframes that are not isolated.

I get this error on my console (on http://elementorlocal.local/):

The Document-Isolation-Policy header has been ignored because the URL's origin was untrustworthy. Please deliver the response using the HTTPS protocol. You can also use the 'localhost' origin instead. See https://www.w3.org/TR/powerful-features/#potentially-trustworthy-origin.

Which makes me think that if I was on a trusted origin, DIP would be enforced and I might get a security error. (This also aligns with the code comment in this PR).

Then also, is it possible you cannot reproduce due to the Gutenburg plugin doing:

remove_action( 'load-post.php', 'wp_set_up_cross_origin_isolation' );
remove_action( 'load-post-new.php', 'wp_set_up_cross_origin_isolation' );

Thanks for bearing with me here guys :D I am just trying my best to understand the full picture and make sure we reach the right conclusion.

@louiswol94
Copy link

louiswol94 commented Mar 10, 2026

Something else that might be important evidence...

I ran our test suite against this PR: https://github.com/elementor/elementor/pull/35068/changes

In this PR I removed the filter and made sure the WP nightly version is used.

From the logs I can see PlayWright used Chromium 139.0.7258.5 which is above 137.

It ran on localhost:8888

And all the tests passed. Meaning everything should be okay :)

@louiswol94
Copy link

I will monitor this thread, but after my latest findings if you guys still do not think this PR is necessary, then I am in agreement not to merge it.

I really want to thank you guys for the work you are doing!

Kind regards
Louis

@adamsilverstein
Copy link
Member Author

I will monitor this thread, but after my latest findings if you guys still do not think this PR is necessary, then I am in agreement not to merge it.

@louiswol94 thanks for the continued testing here. One way to test Beta 3 on an actual site is to install the Beta Tester Plugin - https://wordpress.org/plugins/wordpress-beta-tester/. Install it and set it to download nightlies, then update. Installing the Gutenberg plugin is a good proxy, but doesn't represent the exact code WordPress will release with. If you have some sites running older Elementor versions you could test on that would provide empirical validation.

Hi, sorry to jump in like this - but if this PR doesn't get merged, millions of Elementor sites will become unusable.

@miriamelementor - don't worry, we still have time to get this very small change into the release, but I want to make sure its really needed. We made an architectural change recently (switching the header approach) that may have already fixed the issue. The fix in this PR turns off the feature for Elementor, meaning you won't be able to use it or any of the new capabilities it provides, so i want to make sure we are turning it off for a reason!

@louiswol94
Copy link

Thanks @adamsilverstein - I forgot about the Beta Tester Plugin. I am glad you prompted me to test further.

I installed:

  1. WordPress 7.0-beta3-61869.
  2. Elementor 3.34.4

On a Live website. And get the following:

editor.min.js?ver=3.34.4:2 Uncaught SecurityError: Failed to read a named property 'elementorFrontend' from 'Window': Blocked a frame with origin "https://naharwuz.elementor.cloud" from accessing a cross-origin frame.
    at editor.min.js?ver=3.34.4:2:1259679
    at Editor.onPreviewLoaded (editor.min.js?ver=3.34.4:2:1260247)
    at HTMLIFrameElement.dispatch (load-scripts.php?c=1&load%5Bchunk_0%5D=jquery-core,jquery-migrate,jquery-ui-core,jquery-ui-mouse,underscore,backbone,wp-api-request,wp-hooks&ver=7.0-beta3-61869:2:40035)
    at v.handle (load-scripts.php?c=1&load%5Bchunk_0%5D=jquery-core,jquery-migrate,jquery-ui-core,jquery-ui-mouse,underscore,backbone,wp-api-request,wp-hooks&ver=7.0-beta3-61869:2:38006)
Screenshot 2026-03-10 at 10 47 25 PM Screenshot 2026-03-10 at 10 47 39 PM Screenshot 2026-03-10 at 10 47 54 PM

@louiswol94
Copy link

Here is a snapshot of the DOM:

Screenshot 2026-03-10 at 10 50 55 PM

@westonruter
Copy link
Member

@louiswol94:

Then also, is it possible you cannot reproduce due to the Gutenburg plugin doing:

remove_action( 'load-post.php', 'wp_set_up_cross_origin_isolation' );
remove_action( 'load-post-new.php', 'wp_set_up_cross_origin_isolation' );

Right you are! I deactivated Gutenberg and then I was able to get the error, and this PR fixes the issue.

Copy link
Member

@westonruter westonruter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes the issue with Elementor for me.

Add unit tests verifying that client-side media processing
is disabled on non-secure, non-localhost origins and enabled
on localhost regardless of SSL.
The NonceVerification.Recommended suppression is not needed
here since $_GET['action'] is only used for a simple string
comparison, not for any state-changing operation.
@adamsilverstein
Copy link
Member Author

I added a couple of tests for this in 85d6e62 and it is ready for another review @westonruter @mukeshpanchal27.

I'd like to get this committed asap.

adamsilverstein and others added 3 commits March 10, 2026 16:50
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Copy link
Member

@westonruter westonruter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ship it!

@adamsilverstein
Copy link
Member Author

Ship it!

image

I'm a little disappointed GitHub doesn't offer a way to extend the emojis I can respond with so i can use the ship.

@adamsilverstein
Copy link
Member Author

Checking test failures...

The sideload route is only registered when client-side media
processing is enabled, which now requires SSL or localhost.
Force-enable the filter in affected tests so routes register
correctly in CI.
@adamsilverstein
Copy link
Member Author

Checking test failures...

Ah, since the CI runs on a non-SSL, non-localhost environment, wp_is_client_side_media_processing_enabled() returns false which is breaking some tests. Fixing.

The parent set_up() creates and initializes the REST server
before individual test methods run, so the filter alone is
not enough. Reset the server global and re-fire rest_api_init
after enabling the filter.
@github-actions
Copy link

A commit was made that fixes the Trac ticket referenced in the description of this pull request.

SVN changeset: 61947
GitHub commit: 2bb252a

This PR will be closed, but please confirm the accuracy of this and reopen if there is more work to be done.

@github-actions github-actions bot closed this Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants